﻿using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using CI.Interfaces;
using CI.Mesopotamia;
using Rhino.Mocks;
using CI.Organism;
using CI;

namespace Mesopotamia.UnitTests
{
    [TestFixture]
    public class ScenarioTests
    {
        private IScenario _scenario;
        private IHostingEnvironment _hostingEnvironment;
        private iRobot _fallbackiRobot;
        private IOrganismCollection _organismCollection;

        [SetUp]
        public void Setup()
        {
            _scenario = new ScenarioLocalXML();
            _hostingEnvironment = MockRepository.GenerateStub<IHostingEnvironment>();

        }

        /// <summary>
        /// make sure it check the organism colleciton
        /// </summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "organisms")]
        public void CompareEnvironmentUpdateRequirements_NullIOrganism_CollectionException()
        {
            _scenario.CompareEnvironmentUpdateRequirements(null, _hostingEnvironment);
        }

        /// <summary>
        /// make sure it check the hosting environment
        /// </summary>
        [Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "hostingEnvironment")]
        public void CompareEnvironmentUpdateRequirements_NullIHostingEnvironment_Exception()
        {
            _scenario.CompareEnvironmentUpdateRequirements(new OrganismCollection(), null);
        }

        [Test]
        public void CompareEnvironmentUpdateRequirements_NoDalOrganismsUsedFallBackOrganisms_Equal()
        {
            SetupScenarioWithNoDalOrganisms();
            CheckResulstIsFallBackiRobot();
        }

        [Test]
        public void CompareEnvironmentUpdateRequirements_WithDalOrganismsUsedFallBackOrganisms_Equal()
        {
            SetupScenarioWithNoDalOrganisms(); 
            _organismCollection.AliveAdd(GenerateMockiRobot().Organism);
            CheckResulstIsFallBackiRobot();
        }

        private void CheckResulstIsFallBackiRobot()
        {
            List<IOrganism> organisms = _scenario.CompareEnvironmentUpdateRequirements(_organismCollection, _hostingEnvironment).ToList();
            Assert.AreEqual(_fallbackiRobot, organisms[0].Cells.FindPhysicalZygote());
        }

        private void SetupScenarioWithNoDalOrganisms()
        {
            _fallbackiRobot = GenerateFallbackOrganisms();
            GenerateScenarioRequirements(_fallbackiRobot);

            _scenario.RequiredOrganisms[0].UseFallBackOnly = true;

            SimEnv.Instance.HostEnv = MockRepository.GenerateMock<IHostingEnvironment>();
            SimEnv.Instance.HostEnv.Organisms = new OrganismCollection();

            _organismCollection = MockRepository.GenerateStub<IOrganismCollection>();
            _organismCollection.Alive = new SynchronizedCollection<IOrganism>();
        }

        private void GenerateScenarioRequirements(iRobot irobot)
        {
            var scenarioEntityRequirements = MockRepository.GenerateStub<IScenarioEntityRequirements>();
            scenarioEntityRequirements.OrganismType = irobot;
            scenarioEntityRequirements.Locations = new List<ILocation> { new Location() };
            _scenario.RequiredOrganisms.Add(scenarioEntityRequirements);
        }

        private iRobot GenerateFallbackOrganisms()
        {
            var irobot = GenerateMockiRobot();
            var fallbackOrganism = MockRepository.GenerateStub<IOrganism>();
            fallbackOrganism.Stub(x => x.Zygote()).Return(irobot);
            fallbackOrganism.Cells = MockRepository.GenerateStub<ICellCollection>();
            fallbackOrganism.Cells.Stub(x => x.FindPhysicalZygote()).Return(irobot);
            _scenario.FallBackOrganisms.Add(fallbackOrganism);
            return irobot;
        }

        private static iRobot GenerateMockiRobot()
        {
            var iRobotOrganism = MockRepository.GenerateMock<IOrganism>();
            iRobotOrganism.Stub(x => x.Cells).Return(new CellCollection());
            var irobot = new iRobot(iRobotOrganism, Guid.NewGuid());
            iRobotOrganism.Stub(x => x.Zygote()).Return(irobot);
            return irobot;
        }
    }
}
